package com.globalwave.base;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;

public class SqlParser {

	final private static char PROPERTY_START_FLAG = '[' ;
	final private static char PROPERTY_END_FLAG = ']' ;
	
	final private static char SEGMENT_START_FLAG = '{' ;
	final private static char SEGMENT_END_FLAG = '}' ;

	private Object bean ;
	private Map<String, Object> mapBean ;
	private List<Object> params = new ArrayList<Object>() ;
	
	private String input ;
	
	private StringBuffer output = new StringBuffer() ;
	
	private int current = -1 ;
	private int last ;
	private char c ;
	
	public SqlParser(String input, Object bean) {
		this.input = input ;
		this.last = input.length() ;
		if (bean instanceof Map) {
			this.mapBean = (Map) bean ;
		} else {
			this.bean = bean ;			
		}
	} 	
	
	public String parse() throws Exception {

		while (nextChar()) {			
			if (c == PROPERTY_START_FLAG) {
				propertyStart() ;
			} else if (c == SEGMENT_START_FLAG){
				segmentStart() ;
			} else {
				output.append(c) ;
			}
		}
		
		return output.toString() ;
	}
	
	
	private boolean nextChar() {

		current ++ ;
		
		if (current < last) {
			c = input.charAt(current) ;
			return true ;
		} else {
			return false ;
		}
	}
		
	

	private void propertyStart() throws Exception {

		int start = current + 1;
		
		while (nextChar()) {			
			if (c == PROPERTY_END_FLAG) {
				String perporty = input.substring(start, current) ;
				
				Object value = 
					mapBean == null ? PropertyUtils.getProperty(bean, perporty)
						: mapBean.get(perporty);

				if (value instanceof List) {
					List<Object> l = (List<Object>) value;
					for (int i = 0 ; i < l.size() ; i ++) {
						if (i != 0) {
							output.append(',') ;
							output.append(' ') ;
						}
						params.add(l.get(i)) ;
						output.append('?') ;
					}
				} else {
					params.add(value) ;
					output.append('?') ;					
				}
				return ;
			} 
		}
	}
		

	private void segmentStart() throws Exception {

		//int start = current + 1;
		int paramsStart = params.size() ;
		
		StringBuffer temp = output ;
		
		output = new StringBuffer() ;
		
		while (nextChar()) {			
			if (c == PROPERTY_START_FLAG) {
				propertyStart() ;
			} else if (c == SEGMENT_END_FLAG) {				
				Object lastParam = params.get(params.size() - 1) ;
				
				if (lastParam == null) {
					for (int last = params.size() - 1 ; last >= paramsStart ; last --) {
						params.remove(last) ;
					}
					
					output = temp ;
				} else {
					temp.append(output) ;
				    output = temp ;
				}
				return ;
			} else {
				output.append(c) ;
			}
		}
	}
	
	public List<Object> getParams() {
		return this.params ;
	}
}
